/*
CoE 1186

1186 Entertainment
Reversi Game

ReversiGameBoard.java


-----------------------------------------
ReversiGameBoard

	- Abstract or Concrete:  Concrete
	- List of Superclasses:  GameBoard, MyPanel, JPanel
	- List of Subclasses:  N/A
	- Purpose: Java Reversi Game
	- Collaborations:  Loaded by the ReversiGameRoom, Send Messages to server through ClientApplet
---------------------
	- Attributes:

---------------------
	- Operations:

---------------------
	- Constraints:  N/A

-----------------------------------------
*/

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.*;
import java.util.Random;

public class ReversiGameBoard extends MyPanel {

ReversiGameManager gm;
ClientApplet ca;
ReversiGameRoom room;
String DELIM = "&";
int player1, player2, r;
ReversiGamePiece [][] pieces;

	/*public ReversiGameBoard() {

		ReversiGamePiece [][] pieces = new ReversiGamePiece[8][8];

		setPreferredSize(new Dimension(400,400));
		setBackgroundPosition(MyPanel.STRETCHED);
		setBackgroundImage("files/board.jpg");
		setLayout(new GridLayout(8,8));
		gm = new ReversiGameManager(pieces,this);

		for (int i = 0 ; i < 8 ; i++ )
		{
			for (int j = 0; j < 8 ; j++ )
			{
				pieces[i][j] = new ReversiGamePiece();
				pieces[i][j].addMouseListener(gm);
				add(pieces[i][j]);
			}
		}

		initialize(pieces);
    }*/

    public ReversiGameBoard(ClientApplet ca, ReversiGameRoom room, int player1, int player2) {

		this.ca = ca;
		this.room = room;
		this.player1 = player1;
		this.player2 = player2;

		pieces = new ReversiGamePiece[8][8];

        setPreferredSize(new Dimension(400,400));
		//setBackgroundPosition(MyPanel.STRETCHED);
		//setBackgroundImage("files/board.jpg");
		setLayout(new GridLayout(8,8));
        gm = new ReversiGameManager(pieces,this);

		for (int i = 0 ; i < 8 ; i++ )
		{
			for (int j = 0; j < 8 ; j++ )
			{
				pieces[i][j] = new ReversiGamePiece(ca);
				pieces[i][j].addMouseListener(gm);
				add(pieces[i][j]);
			}
		}

		initialize(pieces);


    }

	public void initialize(ReversiGamePiece [][] pieces)
	{
		pieces[3][3].makeMove(ReversiGamePiece.WHITE);
		pieces[3][4].makeMove(ReversiGamePiece.BLACK);
		pieces[4][4].makeMove(ReversiGamePiece.WHITE);
		pieces[4][3].makeMove(ReversiGamePiece.BLACK);

		Random generator = new Random();
		r = generator.nextInt(1000);
		ca.send("22" + DELIM + "01" + DELIM + r);
		
	}

	public void processMove( String msg)
	{
		String[] msgParts = msg.split(DELIM);
		int msgId = Integer.parseInt(msgParts[1]);

		switch(msgId)
		{
			case 01:
				if (r > Integer.parseInt(msgParts[2]))
				{
					gm.mycolor = ReversiGamePiece.BLACK;
					room.setGamePieceText("Black");
					room.setStatusText("Waiting for other player to go");
				}
				if (r < Integer.parseInt(msgParts[2]))
				{
					gm.mycolor = ReversiGamePiece.WHITE;
					gm.turn = true;
					room.setGamePieceText("White");
					room.setStatusText("It\'s your turn.");
				}
				System.out.println("" + r + " " + Integer.parseInt(msgParts[2]));
				break;
			case 02:
				gm.checkMove(pieces[Integer.parseInt(msgParts[3])][Integer.parseInt(msgParts[4])],Integer.parseInt(msgParts[2]),gm.mycolor);
				room.setStatusText("It\'s your turn.");
				gm.turn = true;
				gm.checkBoard(gm.mycolor);
				break;
			case 03:
				room.setStatusText("It\'s your turn.");
				gm.turn = true;
				gm.checkBoard(gm.mycolor);
				break;
				
		}
	}

}

class ReversiGameManager implements MouseListener
	{
		static int moving;
		boolean turn = false;
		int mycolor,opposite;
		ReversiGamePiece [][] pieces;
		ReversiGameBoard board;

		public ReversiGameManager(ReversiGamePiece [][]  pieces, ReversiGameBoard board)
		{
			this.pieces = pieces;
			this.board = board;
		}

		public void mouseClicked(MouseEvent e)
		{

            ReversiGamePiece theEventer = (ReversiGamePiece)  e.getSource();

			if(theEventer.current == 0)
			{
				 if (turn)
				 {
					if(mycolor == ReversiGamePiece.WHITE)
						opposite = ReversiGamePiece.BLACK;
					else
						opposite = ReversiGamePiece.WHITE;

					 if(checkMove(theEventer,mycolor,opposite))
					 {
						 int x, y;
							for(int i=0;i<8;i++)
							{
								for (int j=0;j<8 ;j++)
								{
									if(pieces[i][j] == theEventer)
									{
										x = i;
										y = j;
										board.ca.send("22" + board.DELIM + "02" + board.DELIM+ mycolor + board.DELIM + x + board.DELIM + y);
										board.room.setStatusText("Waiting for other player to go");
										turn = false;
										if(evalBoard(mycolor) == 3)
											checkBoard(mycolor);
									}
								}
							}

					 }
				 }
			}

		}

		public void checkBoard(int player)
		{
			int black = 0;
			int white = 0;

			switch(evalBoard(player))
			{
				case 1:
					break;
				case 2:
					JOptionPane.showMessageDialog(board, "No Remaining Moves\nPassing Turn", "Message", JOptionPane.ERROR_MESSAGE);
					board.room.setStatusText("Waiting for other player to go");
					board.ca.send("22" + board.DELIM + "03");
					turn = false;
					break;
				case 3:
					for(int i=0;i<8;i++)
					{
						for (int j=0;j<8 ;j++)
						{
							if(pieces[i][j].current == ReversiGamePiece.BLACK){black++;}
							if(pieces[i][j].current == ReversiGamePiece.WHITE){white++;}
						}
					}
					if (black > white)
					{
						if(mycolor == ReversiGamePiece.BLACK)
						{
							JOptionPane.showMessageDialog(board, "You Win!!!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
							turn = false;
							board.ca.send("23" + board.DELIM + board.player1 + board.DELIM + "1");
							board.ca.send("4" + board.DELIM + "0");
						}
						else
						{
							JOptionPane.showMessageDialog(board, "You Lose!!!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
							turn = false;
							board.ca.send("23" + board.DELIM + board.player1 + board.DELIM + "2");
							board.ca.send("4" + board.DELIM + "0");
						}
					}
					else if (white > black)
					{
						if(mycolor == ReversiGamePiece.WHITE)
						{
							JOptionPane.showMessageDialog(board, "You Win!!!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
							turn = false;
							board.ca.send("23" + board.DELIM + board.player1 + board.DELIM + "1");
							board.ca.send("4" + board.DELIM + "0");
						}
						else
						{
							JOptionPane.showMessageDialog(board, "You Lose!!!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
							turn = false;
							board.ca.send("23" + board.DELIM + board.player1 + board.DELIM + "2");
							board.ca.send("4" + board.DELIM + "0");
						}
					}

					else if (white == black)
					{

						JOptionPane.showMessageDialog(board, "It is a Tie!!!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
						turn = false;
						board.ca.send("4" + board.DELIM + "0");
					}
					break;

			}
		}


		private int evalBoard(int player)
		{

		int opposite;

		if(player == ReversiGamePiece.WHITE)
			opposite = ReversiGamePiece.BLACK;
		else
			opposite = ReversiGamePiece.WHITE;


		for (int i = 0 ; i < 8 ; i++ )
		{
			for (int j = 0; j < 8 ; j++ )
			{
				if(pieces[i][j].current == 0)
				{
					boolean moveleft = false;
					moveleft = checkLeft(i,j-1,player,opposite,true,true) || moveleft;
					moveleft = checkUpLeft(i-1,j-1,player,opposite,true,true) || moveleft;
					moveleft = checkUp(i-1,j,player,opposite,true,true) || moveleft;
					moveleft = checkUpRight(i-1,j+1,player,opposite,true,true) || moveleft;
					moveleft = checkRight(i,j+1,player,opposite,true,true) || moveleft;
					moveleft = checkDownRight(i+1,j+1,player,opposite,true,true) || moveleft;
					moveleft = checkDown(i+1,j,player,opposite,true,true) || moveleft;
					moveleft = checkDownLeft(i+1,j-1,player,opposite,true,true) || moveleft;	

					if(moveleft)
					{
						return 1;
					}

				}
			}
		}

		for (int i = 0 ; i < 8 ; i++ )
		{
			for (int j = 0; j < 8 ; j++ )
			{
				if(pieces[i][j].current == 0)
				{
					boolean moveleft = false;
					moveleft = checkLeft(i,j-1,opposite,player,true,true) || moveleft;
					moveleft = checkUpLeft(i-1,j-1,opposite,player,true,true) || moveleft;
					moveleft = checkUp(i-1,j,opposite,player,true,true) || moveleft;
					moveleft = checkUpRight(i-1,j+1,opposite,player,true,true) || moveleft;
					moveleft = checkRight(i,j+1,opposite,player,true,true) || moveleft;
					moveleft = checkDownRight(i+1,j+1,opposite,player,true,true) || moveleft;
					moveleft = checkDown(i+1,j,opposite,player,true,true) || moveleft;
					moveleft = checkDownLeft(i+1,j-1,opposite,player,true,true) || moveleft;	
					if(moveleft)
					{
						return 2;
					}

				}
			}
		}
			
			return 3;

		}

		public boolean checkMove(ReversiGamePiece MadeMove, int current, int opposite)
		{
			int x=0, y=0;
			boolean legal = false;
			for(int i=0;i<8;i++)
			{
				for (int j=0;j<8 ;j++)
				{
					if(pieces[i][j] == MadeMove)
					{
						x = i;
						y = j;
					}
				}
			}

			legal = checkLeft(x,y-1,current,opposite,true,false) || legal;
			legal = checkUpLeft(x-1,y-1,current,opposite,true,false) || legal;
			legal = checkUp(x-1,y,current,opposite,true,false) || legal;
			legal = checkUpRight(x-1,y+1,current,opposite,true,false) || legal;
			legal = checkRight(x,y+1,current,opposite,true,false) || legal;
			legal = checkDownRight(x+1,y+1,current,opposite,true,false) || legal;
			legal = checkDown(x+1,y,current,opposite,true,false) || legal;
			legal = checkDownLeft(x+1,y-1,current,opposite,true,false) || legal;



			if(legal)
			{
				MadeMove.makeMove(current);
				board.repaint();
				return(true);
			}
			else
			{
				return(false);
			}


		}
		private boolean checkLeft(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkLeft(x,y-1,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkUpLeft(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkUpLeft(x-1,y-1,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkUp(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkUp(x-1,y,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkUpRight(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkUpRight(x-1,y+1,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkRight(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkRight(x,y+1,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkDownRight(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkDownRight(x+1,y+1,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkDown(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkDown(x+1,y,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		private boolean checkDownLeft(int x, int y, int current,int opposite, boolean firstrun, boolean evaluating)
	    {
			if (x >= 0 && x <8)
			{
				if(y >= 0 && y <8)
				{
					if(pieces[x][y].current==opposite)
					{
						if(checkDownLeft(x+1,y-1,current,opposite,false,evaluating))
						{
							if(!evaluating)
							pieces[x][y].flipPiece();
							return true;
						}
						else
						{
							return false;
						}
					}
					else if(pieces[x][y].current == current)
					{
						if (firstrun)
						{
							return false;
						}
						else
						{
							return true;
						}
					}
					else
					{
						return false;
					}

				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}

		public void mousePressed(MouseEvent e){}
		public void mouseReleased(MouseEvent e){}
		public void mouseEntered(MouseEvent e){}
		public void mouseExited(MouseEvent e){}
	}

class ReversiGamePiece extends JPanel implements Runnable {
    Image[] picture = new Image[9];
    int totalPictures = 0;
	public final static int BLACK = 1;
	public final static int WHITE = 7;
    int current = 0;
	int temp = 0;
	int go = 0;
    Thread runner;
    int pause = 80;
    String[] imageNames = { "files/0.gif", "files/1.gif", "files/2.gif", "files/3.gif", "files/4.gif", "files/5.gif", "files/6.gif", "files/7.gif" };

    public ReversiGamePiece(ClientApplet ca) {
        super();
        Toolkit kit = Toolkit.getDefaultToolkit();
        for (int i = 0; i < imageNames.length; i++) {
            picture[i] = ca.getImage(ca.getDocumentBase(),imageNames[i]);
        }
        runner = new Thread(this);
    }

	public void makeMove(int current)
	{
		this.current = current;
		temp = current;
		repaint();
	}

	public void flipPiece() {
		temp = current;
		if(current == BLACK){current = WHITE;}
		else if(current == WHITE){current = BLACK;}
		runner = new Thread(this);
		runner.start();
	}

    public void paintComponent(Graphics screen) {
        Graphics2D screen2D = (Graphics2D) screen;
        if (picture[temp] != null) {
            screen2D.drawImage(picture[temp], 0, 0, this);
        }
    }

    public void start() {
        if (runner == null) {
            runner = new Thread(this);
            runner.start();
        }
    }

    public void run() {
        Thread thisThread = Thread.currentThread();
		int running = 1;

			if (temp < current)
			{
				while (running == 1)
				{
					temp++;
					repaint();
					if (temp == current)
					{
						running = 0;
					}
					try {
						Thread.sleep(pause);
					} catch (InterruptedException e) { }
				}
			}
			if (temp > current)
			{
				while (running == 1)
				{
					temp--;
					repaint();
					if (temp == current)
					{
						running = 0;
					}
					try {
						Thread.sleep(pause);
					} catch (InterruptedException e) { }
				}
			}
			stop();
    }

    public void stop() {
        if (runner != null) {
            runner = null;
        }
    }
}
